﻿using System.Net;
using GamFi.API.Application.Exceptions;
using Newtonsoft.Json;

namespace GamFi.API.WEB.Middlewares;

public class ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
{
    public async Task Invoke(HttpContext context)
    {
        try
        {
            await next(context);
        }
        catch (Exception ex)
        {
            await HandleExceptionAsync(context, ex, logger);
        }
    }

    private static Task HandleExceptionAsync(HttpContext context, Exception exception, ILogger<ExceptionHandlingMiddleware> logger)
    {
        HttpStatusCode statusCode;
        string errorMessage;

        switch (exception)
        {
            case UserException userException:
                statusCode = HttpStatusCode.BadRequest;
                errorMessage = userException.Message;
                break;

            case ImageException imageException:
                statusCode = HttpStatusCode.BadRequest;
                errorMessage = imageException.Message;
                break;

            case WalletException walletException:
                statusCode = HttpStatusCode.BadRequest;
                errorMessage = walletException.Message;
                break;

            case ChatException chatException:
                statusCode = HttpStatusCode.BadRequest;
                errorMessage = chatException.Message;
                break;

            case HttpContextException httpContextException:
                statusCode = HttpStatusCode.BadRequest;
                errorMessage = httpContextException.Message;
                break;

            case RequestException requestException:
                statusCode = HttpStatusCode.BadRequest;
                errorMessage = requestException.Message;
                break;

            default:
                statusCode = HttpStatusCode.InternalServerError;
                errorMessage = "An unexpected error occurred.";
                break;
        }

        var log = LogException(context, exception, statusCode, errorMessage);
        
        logger.LogError(log);

        var result = JsonConvert.SerializeObject(new { error = errorMessage });
        context.Response.ContentType = "application/json";
        context.Response.StatusCode = (int)statusCode;
        return context.Response.WriteAsync(result);
    }

    private static string LogException(HttpContext context, Exception exception, HttpStatusCode statusCode,
        string errorMessage)
    {
        return $"""
                    Exception: {exception.GetType().Name}
                    Message: {exception.Message}
                    Status Code: {(int)statusCode} ({statusCode})
                    Path: {context.Request.Path}
                    Method: {context.Request.Method}
                    Query: {context.Request.QueryString}
                    Stack Trace:
                {exception.StackTrace}
                    
                """;
    }
}